package com.koron.plan.web.common;

import com.koron.bean.base.Response;
import com.koron.bean.enums.TimePeriod;
import com.koron.bean.query.OrderItem;
import com.koron.bean.query.PageQuery;
import com.koron.bean.system.staff.StaffBean;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.task.web.entity.CronTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @author twcao
 * @title: CommonUtils
 * @projectName GDH_EAM_V2
 * @description: 共用工具类
 * @date 2021/9/116:37
 */
@Slf4j
public class CommonUtils {

    /**
     * cron表达式的分隔符
     */
    public static final String CRON_SPLIT = " ";

    /**
     * 设置创建人和修改人
     * @param vo 业务数据实体
     * @param staffBean 用户信息
     */
    public static void update(UpdateParameter vo, StaffBean staffBean) {
        Assert.notNull(staffBean, "用户信息为空");
        Assert.notNull(vo, "基础参数为空");
        if(StringUtils.isBlank(vo.getId())) {
            // 新增
            vo.setCreateBy(staffBean.getAccount());
            vo.setCreateByName(staffBean.getName());
            vo.setCreateTime(new Date());
        }
        // 修改
        vo.setUpdateBy(staffBean.getAccount());
        vo.setUpdateByName(staffBean.getName());
        vo.setUpdateTime(new Date());
    }

    public static void update(UpdateParameter vo, String account, String name) {
        Assert.notNull(account, "账号不能为空");
        Assert.notNull(name, "名字不能为空");
        if(StringUtils.isBlank(vo.getId())) {
            // 新增
            vo.setCreateBy(account);
            vo.setCreateByName(name);
            vo.setCreateTime(new Date());
        }
        // 修改
        vo.setUpdateBy(account);
        vo.setUpdateByName(name);
        vo.setUpdateTime(new Date());
    }

    /**
     * 设置删除默认标志（未删除）,如果已存在，不做任何处理
     * @param flag 删除标志位
     */
    public static void update(DeleteFlag flag) {
        Assert.notNull(flag, "实体信息为空");
        if(Objects.isNull(flag.getDeleteFlag())) {
            flag.setDeleteFlag(false);
        }
    }

    /**
     * 批量设置删除默认标志（未删除）,如果已存在，不做任何处理
     * @param flags 删除标志位
     */
    public static void update(List<? extends DeleteFlag> flags) {
        if(CollectionUtils.isEmpty(flags)) {
            return;
        }
        flags.stream().forEach(flag -> update(flag));
    }

    /**
     * 设置排序值,从1开始
     * @param sortable
     */
    public static void sorted(List<? extends Sortable> sortable) {
        if(CollectionUtils.isEmpty(sortable)) {
            return;
        }
        Stream.iterate(0, i -> i + 1).limit(sortable.size()).forEach(i -> sortable.get(i).setSort(i + 1));
    }

    /***
     * convert Date to cron, eg "0 07 10 15 1 ? 2016"
     * @param date  : 时间点
     * @return
     */
    public static String getCron(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
        String formatTimeStr = null;
        if (Objects.nonNull(date)) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    /**
     * 将字符串转为数字
     * @param numStr
     * @return
     */
    public static Integer parse(String numStr) {
        try {
            return Integer.parseInt(numStr);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 是否是正整数
     * @param num
     * @return
     */
    public static boolean isPositive(Integer num) {
        return num != null && num > 0;
    }

    /**
     * 是否是正数
     * @param num
     * @return
     */
    public static boolean isPositive(Double num) {
        return num != null && num > 0;
    }

    /**
     * 将时分秒转成cron表达式
     * @param cronTask
     * @return
     */
    public static String parseStrToCron(CronTask cronTask) {
        Assert.notNull(cronTask, "cron表达式不能为空");
        // 秒
        String seconds = "0";
        // 分
        String mins = cronTask.getMins();
        // 时
        String hours = cronTask.getHours();
        // 天
        String days = cronTask.getDays();
        // 月
        String months = cronTask.getMonths();
        // 周
        String weeks = cronTask.getWeeks();
        // 年
        String years = cronTask.getYears();
        // 若两者都为空，则每天都执行
        if(StringUtils.isAllBlank(days, weeks)) {
            // 如果月份和星期都为空，则每天都执行
            days = "*";
            weeks = "?";
        }
        if(StringUtils.isBlank(days) && StringUtils.equals("?", weeks)) {
            days = "*";
        }
        if(StringUtils.equals("?", days) && StringUtils.isBlank(weeks)) {
            weeks = "*";
        }
        if(StringUtils.isBlank(days) && StringUtils.isNumeric(weeks)) {
            days = "?";
        }
        if(StringUtils.isBlank(weeks) && StringUtils.isNumeric(days)) {
            weeks = "?";
        }
        // 若天为每一天或某一天，则周只能是未知
        if(StringUtils.equals("*", days) || StringUtils.isNumeric(days)) {
            Assert.isTrue(StringUtils.equals("?", weeks), "天、周只能配置一个");
        }
        // 若周为每一天或周几，则天只能是未知
        if(StringUtils.equals("*", weeks) || StringUtils.isNumeric(weeks)) {
            Assert.isTrue(StringUtils.equals("?", days), "天、周只能配置一个");
        }
        // 秒-默认为0
        StringBuilder sb = new StringBuilder(seconds);
        sb.append(CRON_SPLIT);
        // 分-默认为0
        sb.append(StringUtils.isBlank(mins) ? "0" : mins);
        sb.append(CRON_SPLIT);
        // 时-默认8
        sb.append(StringUtils.isBlank(hours) ? "8" : hours);
        sb.append(CRON_SPLIT);
        // 天-无默认
        sb.append(StringUtils.isBlank(days) ? "?" : days);
        sb.append(CRON_SPLIT);
        // 月-如果为空，则所有月份
        sb.append(StringUtils.isBlank(months) ? "*" : months);
        sb.append(CRON_SPLIT);
        // 周-无默认
        sb.append(StringUtils.isBlank(weeks) ? "?" : weeks);
        sb.append(CRON_SPLIT);
        // 年-如果为空，则所有年份
        sb.append(StringUtils.isBlank(years) ? "*" : years);
        return sb.toString();
    }

    /**
     * 获取编码
     * @param prefix 前缀
     * @param length 流水号长度
     * @return 最新的编码
     */
    public static String getCodeNo(String prefix, Integer length) {
        EamUser currentUser = ThreadLocalContext.get();
        String orgName = currentUser.getPrefix();
        Assert.hasText(orgName, "组织编码前缀不能为空");
        // 转成大写
        orgName = StringUtils.upperCase(orgName);
        return CodeTools.getCodeNo(prefix + orgName, length);
    }

    public static <T> T getObject(boolean expression, String msg, Response<T> resp) {
        Assert.isTrue(expression, msg);
        return resp.getData();
    }

    public static <T> T ok(Response<T> resp) {
        return getObject(resp != null && resp.getCode() == 200, resp == null ? "远程调用失败" : resp.getDescription(), resp);
    }

    /**
     * 计算开始时间和结束时间
     * @param taskType 任务类型 1->手动任务，2->定时任务，不提前，3->定时任务，提前
     * @param durationHours 工期，单位小时
     * @param firstTime 定时任务最近一次执行的时间
     * @return 开始时间[0]和结束时间[1]
     */
    public static Date[] computeOrderTime(Integer taskType, Integer durationHours, Date firstTime) {
        Assert.notNull(taskType, "任务生成方式不能为空");
        Assert.notNull(durationHours, "工单周期不能为空");
        Date[] times = new Date[2];
        if(taskType == 1) {
            // 手动下发
            times[0] = new Date();
        }
        if(taskType == 2 || taskType == 3) {
            Assert.notNull(firstTime, "任务执行时间不能为空");
            times[0] = firstTime;
        }
        // 最后一定要带L，否则被认为是int类型，相加后，超过int最大值，导致时间戳反而变小
        times[1] = new Date(times[0].getTime() + durationHours * 3600 * 1000L);
        return times;
    }

    public static void addTableAlias(PageQuery query, String tableAlias) {
        List<OrderItem> orders = query.getOrders();
        if(CollectionUtils.isEmpty(orders)) {
            return;
        }
        orders.stream().forEach(item -> item.setPrefix(tableAlias));
    }

    public static int periodToHour(int timeNum, TimePeriod tp) {
        Assert.isTrue(timeNum >= 0,"数值不能为空");
        Assert.notNull(tp,"时间单位不能为空");
        switch (tp) {
            case HOUR:
                return timeNum;
            case DAY:
                return timeNum * 24;
            case WEEK:
                return timeNum * 7 * 24;
            case MONTH:
                return timeNum * 30 * 24;
            default:
                return timeNum;
        }
    }
}
